package cn.myzf.fort.access.accesscommon.core;


import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.SystemUtils;

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 获取执行路径
 * */

public class Binaries {

    protected static Logger log = Logger.getLogger(Binaries.class.getName());


    public final static String RESOURCE_DIR = "static/";

    public final static String WINDOWS_DIR_32 = "windows-x86/";

    public final static String WINDOWS_DIR_64 = "windows-x86_64/";

    public final static  String LIBRARIES = "libraries.txt";

    protected static String plinkBinary;

    protected static String sshBinary;

    /*标记执行路径状态 已经获取过来就变成true */
    protected static Boolean binariesExtracted;

    public synchronized static int getBitness() {
        String arch;

        arch = System.getProperty("os.arch");
        if (arch.endsWith("86"))
            return 32;
        else if (arch.endsWith("64"))
            return 64;
        else
            throw new IllegalStateException("Cannot interpret 'os.arch' for bitness: " + arch);
    }


    protected static String getWindowsDir() {
        if (getBitness() == 32)
            return WINDOWS_DIR_32;
        else
            return WINDOWS_DIR_64;
    }


    protected static String homeDir() {
        String result;

        result =  System.getProperty("user.home") + File.separator + "fortAccess";
        return result;
    }


    /**
     * 由于系统设计初衷windows通过跳板机登录（windows可以使用各种第三方软件等）
     * 获取windows下exe的执行文件
     *
     * */
    protected static List<String> getLibraries() throws Exception {
        List<String>	result;
        String		resource;
        InputStream is;
        StringBuilder	buf;
        int			c;

        result   = new ArrayList<>();
        resource = RESOURCE_DIR + getWindowsDir() + LIBRARIES;
        is       = null;
        try {
            buf = new StringBuilder();


            is = Binaries.class.getClassLoader().getResourceAsStream(resource);

            while ((c = is.read()) != -1)
                buf.append((char) c);
            result.addAll(Arrays.asList(buf.toString().split("\n")));
        }
        catch (Exception e) {
            throw new IllegalStateException("Failed to read list of libraries from: " + resource);
        }
        finally {
            IOUtils.closeQuietly(is);
        }

        return result;
    }


    protected static void extractBinaries() throws Exception {
        String	homeDir;
        File	dir;
        String	winDir;

        plinkBinary  = "/usr/bin/ssh";

        if (SystemUtils.IS_OS_LINUX || SystemUtils.IS_OS_MAC_OSX) {
            if (!new File(plinkBinary).exists())
                throw new IllegalStateException("ssh not installed (" + sshBinary + ")?");
        }
        else if (SystemUtils.IS_OS_WINDOWS)  {
            homeDir = homeDir();
            if (!new File(homeDir+ File.separator + "plink.exe").exists()) {
                log.info("Setting up plink environment in '" + homeDir + "'...");
                dir = new File(homeDir);
                if (!dir.exists()){
                    log.info("Creating directory: " + dir);
                    if (!dir.mkdirs())
                        throw new IllegalStateException("Failed to create directory: " + dir);
                }
                winDir = getWindowsDir();
                for (String lib : getLibraries()) {
                   plinkBinary =  copyResourceTo(RESOURCE_DIR +winDir, lib,homeDir);
                }
            }else {
                plinkBinary =  homeDir + File.separator + "plink.exe";
            }
            }
        else {
                throw new IllegalStateException(
                        "Unsupported operating system: "
                                + SystemUtils.OS_NAME + "/" + SystemUtils.OS_ARCH + "/" + SystemUtils.OS_VERSION);
            }
    }


    protected static String copyResourceTo(String inDir, String name, String outDir) throws Exception {
        String			result;
        String			resource;
        InputStream 		is;
        BufferedInputStream bis;
        String			outFull;
        File 			out;
        FileOutputStream fos;
        BufferedOutputStream bos;

        result = null;
        is     = null;
        bis    = null;
        fos    = null;
        bos    = null;

        try {
            resource = inDir;
            if (!resource.endsWith("/"))
                resource += "/";
            resource += name;
            outFull = outDir + File.separator + name;
            log.info("Copying resource '" + resource + "' to '" + outFull + "'");
            is  = Binaries.class.getClassLoader().getResourceAsStream(resource);
            bis = new BufferedInputStream(is);
            out = new File(outFull);
            fos = new FileOutputStream(out);
            bos = new BufferedOutputStream(fos);
            IOUtils.copy(bis, bos);
            result = out.getAbsolutePath();
        }
        catch (Exception e) {
            log.log(Level.SEVERE, "Copying failed!", e);

            throw e;
        }
        finally {
            IOUtils.closeQuietly(bis);
            IOUtils.closeQuietly(is);
            IOUtils.closeQuietly(bos);
            IOUtils.closeQuietly(fos);
        }

        return result;
    }


    public static String rsyncBinary() throws Exception {
        if (binariesExtracted == null)
            extractBinaries();
        return plinkBinary;
    }


    public static void closeQuietly(final Closeable closeable) {
        try {
            if (closeable != null) {
                closeable.close();
            }
        } catch (final IOException ioe) {
            // ignore
        }
    }
}
